/* Copyright (c) 2022 渝州大数据实验室
 *
 * Lanius is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.yzbdl.lanius.orchestrate.serv.service.task.impl;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.yzbdl.lanius.orchestrate.serv.entity.task.TaskPlan;
import org.yzbdl.lanius.orchestrate.serv.entity.task.TaskPlanGroup;
import org.yzbdl.lanius.orchestrate.serv.mapper.task.TaskPlanGroupMapper;
import org.yzbdl.lanius.orchestrate.serv.mapper.task.TaskPlanMapper;
import org.yzbdl.lanius.orchestrate.serv.service.task.TaskPlanGroupService;
import org.yzbdl.lanius.orchestrate.serv.vo.task.TaskPlanGroupVO;
import org.yzbdl.lanius.orchestrate.common.exception.runtime.BusinessException;
import org.yzbdl.lanius.orchestrate.common.utils.MessageUtil;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 任务编排分组service实现类
 *
 * @author jinchunzhao@yzbdl.ac.cn
 * @date 2022-04-07 16:02
 */
@Service
@Slf4j
public class TaskPlanGroupServiceImpl extends ServiceImpl<TaskPlanGroupMapper, TaskPlanGroup>
    implements TaskPlanGroupService {

    @Autowired
    private TaskPlanMapper taskPlanMapper;

    @Override
    public Boolean saveEntity(TaskPlanGroup taskPlanGroup) {
        taskPlanGroup.setId(null);

        // 校验待修改的分组名称在库中是否存在重复的
        LambdaQueryWrapper<TaskPlanGroup> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TaskPlanGroup::getGroupName, taskPlanGroup.getGroupName());
        TaskPlanGroup planGroup = this.getOne(queryWrapper);
        if (Objects.nonNull(planGroup)) {
            throw new BusinessException(MessageUtil.get("task.group.name_exist"));
        }

        Long pid = taskPlanGroup.getPid();
        if (Objects.nonNull(pid)){
            List<TaskPlanGroup> parents = this.baseMapper.getParentsById(pid);
            if (CollectionUtils.isNotEmpty(parents) && parents.size() > 4){
                throw new BusinessException(MessageUtil.get("task.group.level_max_num"));
            }
        }

        boolean save = this.save(taskPlanGroup);
        if (save) {
            return save;
        }
        throw new BusinessException(MessageUtil.get("task.add_error"));
    }

    @Override
    public Boolean updateEntity(TaskPlanGroup taskPlanGroup) {
        if (Objects.isNull(taskPlanGroup.getId())) {
            throw new BusinessException(MessageUtil.get("task.group.id_not_empty"));
        }
        // 校验待修改的分组名称（除去自身）在库中是否存在重复的
        LambdaQueryWrapper<TaskPlanGroup> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TaskPlanGroup::getGroupName, taskPlanGroup.getGroupName());
        queryWrapper.ne(TaskPlanGroup::getId, taskPlanGroup.getId());
        TaskPlanGroup planGroup = this.getOne(queryWrapper);
        if (Objects.nonNull(planGroup)) {
            throw new BusinessException(MessageUtil.get("task.group.name_exist"));
        }
        boolean update = this.updateById(taskPlanGroup);
        if (update) {
            return update;
        }
        throw new BusinessException(MessageUtil.get("task.update_error"));
    }

    @Override
    public Boolean batchUpdateEntity(List<TaskPlanGroup> taskPlanGroups) {

        // 获取分组名称集合
        List<String> groupNames =
            taskPlanGroups.stream().map(TaskPlanGroup::getGroupName).distinct().collect(Collectors.toList());
        if (groupNames.size() < taskPlanGroups.size()) {
            throw new BusinessException(MessageUtil.get("task.group.update_batch_repeat_name"));
        }

        // 过滤ID为空的数据
        List<TaskPlanGroup> groupList =
            taskPlanGroups.stream().filter(item -> Objects.nonNull(item.getId())).collect(Collectors.toList());
        // 获取分组ID集合
        List<Long> groupIds = groupList.stream().map(TaskPlanGroup::getId).collect(Collectors.toList());

        // 根据条件查询数据
        LambdaQueryWrapper<TaskPlanGroup> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(TaskPlanGroup::getGroupName, groupNames);
        queryWrapper.notIn(TaskPlanGroup::getId, groupIds);
        List<TaskPlanGroup> planGroupList = this.list(queryWrapper);
        if (CollectionUtils.isNotEmpty(planGroupList)) {
            throw new BusinessException(MessageUtil.get("task.group.name_exist"));
        }
        boolean batchUpdate = this.updateBatchById(groupList, groupList.size());
        if (batchUpdate) {
            return batchUpdate;
        }
        throw new BusinessException(MessageUtil.get("task.update_error"));
    }

    @Override
    public Boolean deleteEntity(Long id) {

        // 校验是否存在子节点
        LambdaQueryWrapper<TaskPlanGroup> taskPlanGroupQueryWrapper = new LambdaQueryWrapper<>();
        taskPlanGroupQueryWrapper.eq(TaskPlanGroup::getPid, id);
        taskPlanGroupQueryWrapper.last("LIMIT 1");
        TaskPlanGroup planGroup = this.getOne(taskPlanGroupQueryWrapper);
        if (Objects.nonNull(planGroup)) {
            throw new BusinessException(MessageUtil.get("task.group.delete_child_exist"));
        }

        // 校验分组下面是否存在任务编排
        LambdaQueryWrapper<TaskPlan> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TaskPlan::getGroupId, id);
        queryWrapper.last("LIMIT 1");
        TaskPlan taskPlan = taskPlanMapper.selectOne(queryWrapper);
        if (Objects.nonNull(taskPlan)) {
            throw new BusinessException(MessageUtil.get("task.group.delete_task_exist"));
        }

        boolean remove = this.removeById(id);
        if (remove) {
            return remove;
        }
        throw new BusinessException(MessageUtil.get("task.delete_error"));
    }

    @Override
    public List<TaskPlanGroupVO> treeList() {
        List<TaskPlanGroupVO> list = this.baseMapper.treeList();
        return dealTree(list);
    }

    @Override
    public List<TaskPlanGroupVO> queryTaskGroupTreeForTaskPlan() {
        List<TaskPlanGroup> list = this.list();
        JSONArray jsonArray = JSONUtil.parseArray(JSONUtil.toJsonStr(list));
        List<TaskPlanGroupVO> groupVOList = JSONUtil.toList(jsonArray,TaskPlanGroupVO.class);

        // 数据构建为树形结构
        return dealTree(groupVOList);
    }

    @Override
    public Boolean checkRepeatGroup(TaskPlanGroup taskPlanGroup) {

        if (Objects.isNull(taskPlanGroup.getId())) {
            throw new BusinessException(MessageUtil.get("task.group.id_not_empty"));
        }
        LambdaQueryWrapper<TaskPlanGroup> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TaskPlanGroup::getGroupName, taskPlanGroup.getGroupName());
        queryWrapper.ne(TaskPlanGroup::getId, taskPlanGroup.getId());
        TaskPlanGroup planGroup = this.getOne(queryWrapper);
        if (Objects.isNull(planGroup)) {
            return Boolean.FALSE;
        } else {
            return Boolean.TRUE;
        }
    }

    /**
     * 将分组数据处理为一个树形结构
     *
     * @param list
     *        数据列表
     * @return
     *       树形数据信息
     */
    private List<TaskPlanGroupVO> dealTree(List<TaskPlanGroupVO> list) {
        List<TaskPlanGroupVO> result;
        Integer level = 1;
        result =
            list.stream().filter(taskPlanGroupVO -> Objects.isNull(taskPlanGroupVO.getPid())).peek(taskPlanGroupVO -> {
                taskPlanGroupVO.setLevel(level);
                taskPlanGroupVO.setChildren(getChildren(taskPlanGroupVO, list,level));
            }).collect(Collectors.toList());
        return result;
    }

    /**
     * 递归获取子节点
     *
     * @param root
     *        当前节点
     * @param all
     *        所有的数据
     * @param level
     *        层级
     * @return
     *       子节点集合
     */
    private List<TaskPlanGroupVO> getChildren(TaskPlanGroupVO root, List<TaskPlanGroupVO> all,Integer level) {
        List<TaskPlanGroupVO> children;
        Integer tempLevel = level + 1;
        children = all.stream().filter(taskPlanGroupVO -> Objects.equals(taskPlanGroupVO.getPid(), root.getId()))
            .peek(taskPlanGroupVO -> {
                taskPlanGroupVO.setLevel(tempLevel);
                taskPlanGroupVO.setChildren(getChildren(taskPlanGroupVO, all,tempLevel));
                taskPlanGroupVO.setIsChild(true);
            }).collect(Collectors.toList());
        return children;
    }
}
